package com.vhall.component.service.room.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.dao.data.AccountForDataMapper;
import com.vhall.component.dao.livecolumn.LiveColumnMapper;
import com.vhall.component.dao.room.*;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.account.GuosenStaffEntity;
import com.vhall.component.entity.account.dto.IndexDto;
import com.vhall.component.entity.account.enums.RoleNameEnum;
import com.vhall.component.entity.common.CachePage;
import com.vhall.component.entity.data.enums.SelectTimeIntervalOptionsEnum;
import com.vhall.component.entity.data.vo.UserBasicStatisticsRspVO;
import com.vhall.component.entity.data.vo.UserParamVO;
import com.vhall.component.entity.export.dto.AdminExportRoomQueryCondition;
import com.vhall.component.entity.guosen.dto.GetTghInfoDTO;
import com.vhall.component.entity.inav.vo.*;
import com.vhall.component.entity.livecolumn.entity.LiveColumnEntity;
import com.vhall.component.entity.rebroadcast.vo.ListReqVo;
import com.vhall.component.entity.record.vo.RoomRspVO;
import com.vhall.component.entity.room.RoomConfig;
import com.vhall.component.entity.room.dto.*;
import com.vhall.component.entity.room.entity.*;
import com.vhall.component.entity.room.enums.LiveContentTypeEnum;
import com.vhall.component.entity.room.enums.LiveRormalEnum;
import com.vhall.component.entity.room.enums.RoomJoinsPreLiveEnum;
import com.vhall.component.entity.room.enums.RoomStatusEnum;
import com.vhall.component.entity.room.vo.*;
import com.vhall.component.entity.thirduser.ThirdUserVO;
import com.vhall.component.entity.thirduser.enums.ThirdUserTypeEnum;
import com.vhall.component.entity.thirduser.vo.GuoxinInvestmentAdvisorTeamDTO;
import com.vhall.component.framework.common.constant.CommonConstant;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.annotation.RedisSpinLock;
import com.vhall.component.plugin.common.constant.ConstStr;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.properties.ThirdPartyProperties;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.core.service.GuoXinService;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.account.GuosenStaffService;
import com.vhall.component.service.guosen.ExternalLiveStatsService;
import com.vhall.component.service.room.AnchorRoomRelationService;
import com.vhall.component.service.room.RoomCacheService;
import com.vhall.component.service.room.RoomInnerService;
import com.vhall.component.service.room.RoomJoinService;
import com.vhall.component.service.room.assembler.RoomJoinsAssembler;
import com.vhall.component.service.room.common.RoomInfoQueryType;
import com.vhall.component.service.room.concant.RoomConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.vhall.component.plugin.common.constant.RedisKey.RESOURCE_IMAGE_GX;

/**
 * @author guoxin.wang
 * @date 2021-06-08 14:40
 */
@Slf4j
@Service
public class RoomInnerServiceImpl implements RoomInnerService {

    @Value("${vhall.account.default-avatar}")
    private String defaultAvatar;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private RoomJoinService roomJoinService;

    @Autowired
    private RoomJoinsMapper roomJoinsMapper;

    @Autowired
    private RoomExtendsMapper roomExtendsMapper;

    @Autowired
    private PaasService paasService;

    @Autowired
    private SupplyMapper supplyMapper;

    @Autowired
    private RoomCacheService roomCacheService;

    @Resource
    private RoomJoinsAssembler roomJoinsAssembler;

    @Autowired
    private RoomConfigMapper roomConfigMapper;

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private LiveColumnMapper liveColumnMapper;

    private static final String LIMIT_1 = "limit 1";

    @Value("${guoxin.column.default_name:''}")
    private String defaultName;
    @Value("${default.column-image-url:'https://gslive.guosen.com.cn/gsoss/c29810c1223a471a9ac28f2de2f88cdb.png'}")
    private String defaultColumnImageUrl;

    @Resource
    private RoomStatsExpansionMapper roomStatsExpansionMapper;
    @Resource
    private AccountForDataMapper accountForDataMapper;

    @Resource
    private AnchorRoomRelationService anchorRoomRelationService;
    @Resource
    private GuosenStaffService guosenStaffService;
    @Resource
    private ThirdPartyProperties thirdPartyProperties;
    @Resource
    private GuoXinService guoXinService;
    @Resource
    private ExternalLiveStatsService externalLiveStatsService;

    @Override
    public RoomsEntityDTO getRoomInfo(String roomId) {
        //先查缓存,存在则直接返回
        String cacheKey = RedisKey.ROOM_INFO_BY_ROOM_ID + roomId;
        Object cachedObj = redisTemplate.opsForValue().get(cacheKey);
        if (Objects.nonNull(cachedObj)) {
            return JSON.parseObject(cachedObj.toString(), RoomsEntityDTO.class);
        }
        return cacheAndHandleGetRoomInfo(roomId, cacheKey, RoomInfoQueryType.ROOM_ID.getValue());
    }

    @Override
    public RoomsEntityDTO getRoomInfoByIlId(String ilId) {
        String cacheKey = RedisKey.ROOM_INFO_BY_ROOM_ID + ilId;
        Object cachedObj = redisTemplate.opsForValue().get(cacheKey);
        if (Objects.nonNull(cachedObj)) {
            return JSON.parseObject(cachedObj.toString(), RoomsEntityDTO.class);
        }
        return cacheAndHandleGetRoomInfo(ilId, cacheKey, RoomInfoQueryType.IL_ID.getValue());
    }

    @RedisSpinLock(redisKey = "#cacheKey", expireTime = 10 * 1000)
    @Override
    public RoomsEntityDTO cacheAndHandleGetRoomInfo(String infoId, String cacheKey, int queryType) {
        // 必须要有从缓存再次获取，用于递归时跳出逻辑
        Object cachedObj = redisTemplate.opsForValue().get(cacheKey);
        if (Objects.nonNull(cachedObj)) {
            return JSON.parseObject(cachedObj.toString(), RoomsEntityDTO.class);
        }

        LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
        if (queryType == RoomInfoQueryType.ROOM_ID.getValue()) {
            wrapper.eq(RoomsEntity::getRoomId, infoId);
        } else if (queryType == RoomInfoQueryType.IL_ID.getValue()) {
            wrapper.eq(RoomsEntity::getIlId, infoId);
        } else {
            log.error("房间信息查询失败，queryType类型不支持，queryType={}", queryType);
            return null;
        }
        wrapper.isNull(RoomsEntity::getDeletedAt);

        wrapper.last(LIMIT_1);
        RoomsEntity entity = roomMapper.selectOne(wrapper);
        if (entity == null) {
            return null;
        }

        RoomsEntityDTO entityDTO = new RoomsEntityDTO();
        BeanUtils.copyProperties(entity, entityDTO);

        entityDTO.setLiveContentTypeName(LiveContentTypeEnum.getDescription(entityDTO.getLiveContentType()));

        //获取栏目名称
        String columnName = defaultName;
        Object imageUrl = redisTemplate.opsForValue().get(RESOURCE_IMAGE_GX);
        String columnImageUrl = defaultColumnImageUrl;
        if (Objects.nonNull(imageUrl)) {
            columnImageUrl = imageUrl.toString();
        }
        if (entityDTO.getColumnId() != null) {
            LiveColumnEntity liveColumnEntity = liveColumnMapper.selectById(entityDTO.getColumnId());
            if (liveColumnEntity != null) {
                columnName = liveColumnEntity.getName();
                columnImageUrl = liveColumnEntity.getColumnImageUrl();
            }
        }

        entityDTO.setColumnName(columnName);
        entityDTO.setColumnImageUrl(columnImageUrl);

        // 设置房间缓存值
        setRoomInfoToCache(entityDTO);
        return entityDTO;
    }

    private void setRoomInfoToCache(RoomsEntityDTO info) {
        // 设置两个缓存，一个是roomId,一个是ilId。在房间数据更新的时候删除掉缓存。
        redisTemplate.opsForValue().set(RedisKey.ROOM_INFO_BY_ROOM_ID + info.getRoomId(), JsonUtil.toJsonString(info), 1, TimeUnit.DAYS);
        redisTemplate.opsForValue().set(RedisKey.ROOM_INFO_BY_ROOM_ID + info.getIlId(), JsonUtil.toJsonString(info), 1, TimeUnit.DAYS);
    }

    @Override
    public void checkRoomId(String roomId) {
        boolean matches = Pattern.matches("[0-9a-zA-Z_]{1,32}", roomId);
        RoomsEntityDTO roomInfo = getRoomInfo(roomId);
        if (!matches || roomInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
    }

    @Override
    public List<RoomsEntityDTO> getRoomInfoByRoomIds(List<String> roomIds) {
        List<RoomsEntityDTO> list = new ArrayList<>();
        for (String roomId : roomIds) {
            RoomsEntityDTO roomInfo = getRoomInfo(roomId);
            if (Objects.nonNull(roomInfo)) {
                list.add(roomInfo);
            }
        }
        return list;
    }

    @Override
    public List<RoomsEntityDTO> getRoomInfoByIlIds(List<Integer> ilIds) {
        List<RoomsEntity> roomsEntities = roomMapper.selectBatchIds(ilIds);
        return BeanCopyUtil.batchCopy(roomsEntities, RoomsEntityDTO::new);
    }

    /**
     * 高频接口
     * 根据房间id与账户id查询房间参会信息
     *
     * @param roomId    房间id
     * @param accountId 账户id
     */
    @Override
    public RoomJoinsEntityDTO getRoomJoinInfo(Integer accountId, String roomId) {
        //通过房间id和用户id在缓存中获取对应参会成员
        RoomJoinsEntity roomJoins = roomCacheService.getCachedRoomJoins(roomId, accountId);
        //判断缓存数据是否存在
        if (Objects.isNull(roomJoins)) {
            return null;
        }
        //参数实体类转成参会DTO
        return roomJoinsAssembler.joinsEntityToDTO(roomJoins);
    }


    @Override
    public RoomSupplyEntityDTO getRoomSupplyByRoomId(String roomId) {
        RoomSupplyEntityDTO dto = new RoomSupplyEntityDTO();
        LambdaQueryWrapper<RoomSupplyEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomSupplyEntity::getRoomId, roomId);
        RoomSupplyEntity entity = supplyMapper.selectOne(wrapper);
        if (entity == null) {
            return null;
        }
        BeanUtils.copyProperties(entity, dto);
        return dto;
    }

    @Override
    public void updateConfigValueByRoomId(String roomId, Integer status, String type) {
        //获取该房间下对应的功能开关状态
        RoomConfig roomConfig = roomConfigMapper.selectOne(new LambdaQueryWrapper<RoomConfig>()
                .eq(RoomConfig::getRoomId, roomId)
                .eq(RoomConfig::getConfigKey, type));
        //判断开关状态与传入状态不同 则更新
        if (Objects.nonNull(roomConfig) && !status.equals(roomConfig.getConfigValue())) {
            roomConfig.setConfigValue(status);
            roomConfig.setUpdatedAt(LocalDateTime.now());
            roomConfigMapper.updateById(roomConfig);
        }
    }

    @Override
    public void insertOrUpdateRoomConfigByAccountId(Integer accountId, Integer status, String type) {
        RoomConfig roomConfig = roomConfigMapper.selectOne(new LambdaQueryWrapper<RoomConfig>()
                .eq(RoomConfig::getAccountId, accountId)
                .eq(RoomConfig::getRoomId, String.valueOf(0))
                .eq(RoomConfig::getConfigKey, type)
                .last(LIMIT_1));
        if (Objects.isNull(roomConfig)) {
            roomConfig = new RoomConfig();
            roomConfig.setRoomId(String.valueOf(0));
            roomConfig.setIlId(0);
            roomConfig.setAccountId(accountId);
            roomConfig.setConfigValue(status);
            roomConfig.setConfigKey(type);
            roomConfig.setCreatedAt(LocalDateTime.now());
            roomConfig.setUpdatedAt(LocalDateTime.now());
            roomConfigMapper.insert(roomConfig);
        } else {
            if (!status.equals(roomConfig.getConfigValue())) {
                roomConfig.setConfigValue(status);
                roomConfig.setUpdatedAt(LocalDateTime.now());
                roomConfigMapper.updateById(roomConfig);
            }
        }
    }

    /**
     * 根据accountId与关键字获取房间列表
     *
     * @param reqVO 请求参数
     * @return Page
     */
    @Override
    public Page<RoomsEntityVO> getRoomsListByAccountId(RoomInnerListVO reqVO) {
        int currPage = reqVO.getPage() == null ? 1 : reqVO.getPage();
        int pageSize = reqVO.getPageSize() == null ? 20 : reqVO.getPageSize();
        Page<RoomsEntity> page = new Page<>(currPage, pageSize);
        LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomsEntity::getAccountId, reqVO.getAccountId());
        if (StringUtils.isNotEmpty(reqVO.getExcludeRoomIds())) {
            final String[] split = reqVO.getExcludeRoomIds().split(",");
            final List<String> strings = Arrays.asList(split);
            wrapper.notIn(RoomsEntity::getRoomId, strings);
        }
        wrapper.orderByDesc(RoomsEntity::getCreatedAt);
        if (!StringUtils.isBlank(reqVO.getKeyword())) {
            wrapper.and(r -> r.like(RoomsEntity::getSubject, reqVO.getKeyword())
                    .or()
                    .like(RoomsEntity::getIlId, reqVO.getKeyword()));
        }
        page = roomMapper.selectPage(page, wrapper);
        List<RoomsEntityVO> rooms = new ArrayList<>();
        page.getRecords().forEach(room -> rooms.add(convertToRoomsEntityVO(room)));
        Page<RoomsEntityVO> roomsEntityVOPage = new Page<>();
        roomsEntityVOPage.setRecords(rooms);
        roomsEntityVOPage.setCurrent(currPage);
        roomsEntityVOPage.setTotal(page.getTotal());
        roomsEntityVOPage.setSize(page.getSize());
        roomsEntityVOPage.setPages(page.getPages());
        return roomsEntityVOPage;
    }

    @Override
    public Boolean setGiftFrequency(String roomId, Integer giftFrequency) {
        RoomsEntityDTO roomsEntityDTO = new RoomsEntityDTO();
        roomsEntityDTO.setRoomId(roomId);
        roomsEntityDTO.setGiftFrequency(giftFrequency);
        return roomInnerService.updateByIl(roomsEntityDTO) > 0;

    }


    @Override
    public Boolean setQuestionFlag(Integer joinId, Integer flag) {
        return roomJoinService.updateQuestionFlag(joinId, flag);
    }

    @Override
    public List<RoomsEntityDTO> listOnlineChannel() {
        List<RoomsEntityDTO> result = new ArrayList<>();
        QueryWrapper<RoomsEntity> where = new QueryWrapper<>();
        where.eq("status", com.vhall.component.plugin.common.constant.RoomConstant.STATUS_START);
        List<RoomsEntity> roomsEntities = roomMapper.selectList(where);
        for (RoomsEntity single : roomsEntities) {
            RoomsEntityDTO singleNew = new RoomsEntityDTO();
            BeanUtils.copyProperties(single, singleNew);
            result.add(singleNew);
        }
        return result;
    }

    @Override
    public List<RoomsEntityDTO> listOnlineChannelOnAccount(Integer accountId) {
        List<RoomsEntityDTO> result = new ArrayList<>();
        accountId = Optional.ofNullable(accountId).orElse(0);
        List<RoomsEntity> roomsEntities = roomMapper.selectList(Wrappers.<RoomsEntity>lambdaQuery()
                .eq(RoomsEntity::getStatus, com.vhall.component.plugin.common.constant.RoomConstant.STATUS_START)
                .eq(RoomsEntity::getAccountId, accountId)
        );
        for (RoomsEntity single : roomsEntities) {
            RoomsEntityDTO singleNew = new RoomsEntityDTO();
            BeanUtils.copyProperties(single, singleNew);
            result.add(singleNew);
        }
        return result;
    }

    @Override
    public GetOnlineListRspVO getOnlineList(GetOnlineListReqVO reqVO) {

        //这个代码 整个 逻辑的意思 大致是  先拿着主持人和上麦的用户的id
        // 做一下  在线检测  paasService.checkUserOnlineByChannel

        //然后 得到   一个  onlineList  这里面 放的是  主持人和上麦的用户
        //  以及 得到一个  speakArr  这里面就是  上麦的用户

        //然后  直接 查询 在线用户列表  paasService.getUserIdList  得到 在线用户列表的id
        //然后 查询  room_jions表里面的  role_name为2的观众


        //  最后把两个集合合并起来


        //  这个  specialList里面 放的 其实就是上麦的用户 加 主持人
        List<GetRoomJoinsDataDTO> specialList = new ArrayList<>();


        //这个 onlineList 里面 放的 其实就是主持人 和 上麦的用户
        List<GetRoomJoinsDataDTO> onlineList = new LinkedList<>();


        List<GetRoomJoinsDataDTO> joinsList = new LinkedList<>();
        RoomsEntityDTO roomModel = getRoomInfo(reqVO.getRoomId());
        if (roomModel == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }

        //主要是 用于 去重使用
        Set<String> accountSet = new HashSet<>();
        if (StringUtils.isBlank(reqVO.getNickname()) && reqVO.getPage() == 1) {
            // 获取上麦用户
            LinkedList<GetRoomJoinsDataDTO> speakers = getSpeakUsers(reqVO.getRoomId());
            //获取未上麦的助理/嘉宾用户 这里面 带 主持人
            LinkedList<GetRoomJoinsDataDTO> specialUser = getSpecialUsers(reqVO.getRoomId(), null);


            // 上麦用户在前
            specialList.addAll(speakers);
            // 未上麦的助理/嘉宾在后
            specialList.addAll(specialUser);
            // 判断是否在线
            Map<String, Object> online = paasService.checkUserOnlineByChannel(roomModel.getChannelId(), getAccountIdList(specialList));

            //  onlie map里面 放的 是  主持人  和 上麦用户
            for (GetRoomJoinsDataDTO item : specialList) {
                String accountId = item.getAccountId().toString();
                // 判断当前的accountId是否是online集合的键
                boolean containsKey = online.containsKey(accountId);
                // 判断当前的accountId在online集合中的值是否>0
                boolean isLt = (Integer) online.get(accountId) > 0;
                // 判断当前角色是否是主持人(1)
                boolean equals = com.vhall.component.plugin.common.constant.RoomConstant.HOST.equals(item.getRoleName());
                if ((containsKey && isLt) || equals) {
                    if (accountSet.contains(accountId)) {
                        continue;
                    }
                    onlineList.add(item);
                    accountSet.add(accountId);
                }
            }

        }
        //在线用户
        Integer pageSize = reqVO.getPagesize() > 200 ? 200 : reqVO.getPagesize();
        List<Integer> userIdList = paasService.getUserIdList(roomModel.getChannelId(), reqVO.getPage(), pageSize);
        //去重
        userIdList = userIdList.stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(userIdList)) {


            //实际上 这个 代码 查询的 是 观众  就是  room_joins表里面 role_name 为2 的 观众
            LambdaQueryWrapper<RoomJoinsEntity> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(RoomJoinsEntity::getRoomId, reqVO.getRoomId())
                    .in(RoomJoinsEntity::getAccountId, userIdList);
            if (StringUtils.isNotBlank(reqVO.getNickname())) {
                queryWrapper.eq(RoomJoinsEntity::getNickname, reqVO.getNickname());
            } else {
                queryWrapper.eq(RoomJoinsEntity::getRoleName, "2");
            }
            List<RoomJoinsEntity> roomJoinsEntityList = roomJoinsMapper.selectList(queryWrapper);
            // 获取上麦中的用户id列表
            Set<Integer> waitingForWheatAccountIds = roomCacheService.listCachedWaitingForWheatAccountId(reqVO.getRoomId());
            for (RoomJoinsEntity roomJoinsEntity : roomJoinsEntityList) {
                //如果在线上麦用户集合已添加，参会用户集合则不用再次添加，避免同一用户返回两次
                if (!accountSet.contains(String.valueOf(roomJoinsEntity.getAccountId()))) {
                    GetRoomJoinsDataDTO dto = new GetRoomJoinsDataDTO();
                    BeanUtils.copyProperties(roomJoinsEntity, dto);
                    GetRoomJoinsDataDTO roomJoinsDataDTO = onlineInavAttr(dto, 0, 0, 0, 0);
                    // 判断上麦中
                    if (CollectionUtils.isNotEmpty(waitingForWheatAccountIds) && waitingForWheatAccountIds
                            .contains(roomJoinsEntity.getAccountId())) {
                        roomJoinsDataDTO.setIsSpeak(2);
                        // 0代表没有上麦   1代表在 麦上面   2代表上麦中
                    }
                    //1:申请中 0：未申请
                    String key = RedisKey.INTERACT_HANDSUP + roomJoinsEntity.getAccountId();
                    if ("1".equals(String.valueOf(redisTemplate.opsForValue().get(key)))) {
                        roomJoinsDataDTO.setIsApply(1);
                    } else {
                        roomJoinsDataDTO.setIsApply(0);
                    }
                    joinsList.add(roomJoinsDataDTO);
                }
            }
        }
        ArrayList<GetRoomJoinsDataDTO> resultList = new ArrayList<>();
        //主持人和上麦的用户
        resultList.addAll(onlineList);
        //主要是观众用户
        resultList.addAll(joinsList);
        List<GetOnlineListDataRspVO> returnList = new LinkedList<>();
        resultList.forEach(r -> {
            GetOnlineListDataRspVO getOnlineListDataRspVO = new GetOnlineListDataRspVO();
            BeanUtils.copyProperties(r, getOnlineListDataRspVO);
            getOnlineListDataRspVO.setAccountId(r.getAccountId().toString());
            returnList.add(getOnlineListDataRspVO);
        });

        // 统一昵称处理
        assemblyNickName(returnList);

        GetOnlineListRspVO resultVo = new GetOnlineListRspVO();
        resultVo.setTotal(getOnlineCount(reqVO.getRoomId()));
        resultVo.setPage(reqVO.getPage().toString());
        resultVo.setPagesize(reqVO.getPagesize());
        resultVo.setList(returnList);
        return resultVo;
    }

    private void assemblyNickName(List<GetOnlineListDataRspVO> returnList) {
        if (CollectionUtils.isNotEmpty(returnList)) {
            List<Integer> accountIdList = returnList.stream().map(e -> Integer.valueOf(e.getAccountId())).collect(Collectors.toList());
            List<AccountEntity> accountEntityList = accountMapper.selectBatchIds(accountIdList);
            Map<Integer, String> stringMap = accountEntityList.stream().collect(Collectors.toMap(AccountEntity::getAccountId, AccountEntity::getNickname));

            for (GetOnlineListDataRspVO dataRspVO : returnList) {
                dataRspVO.setNickname(stringMap.get(Integer.valueOf(dataRspVO.getAccountId())));
            }

        }
    }


    @Override
    public UserListPage<GetUserListRspVO> getUserList(GetUserListReqVO reqVO) {
        LinkedList<GetUserListRspVO> result = new LinkedList<>();
        String roomId = reqVO.getRoomId();
        RoomsEntityDTO room = getRoomInfo(roomId);
        List<Integer> speakArr = new ArrayList<>();
        if (null != room) {
            // 上麦用户
            LinkedList<GetRoomJoinsDataDTO> speakList = getSpeakUsers(roomId);
            if (CollectionUtils.isNotEmpty(speakList)) {
                for (GetRoomJoinsDataDTO single : speakList) {
                    speakArr.add(single.getAccountId());
                }
            }
            if (CollectionUtils.isNotEmpty(speakArr)) {
                getUserListRspVO(roomId, speakArr, room, speakList, result);
            }
        }
        return new UserListPage<>(1, Math.max(result.size(), 20), result.size(), result);
    }

    private void getUserListRspVO(String roomId, List<Integer> speakArr, RoomsEntityDTO room,
                                  LinkedList<GetRoomJoinsDataDTO> speakList, LinkedList<GetUserListRspVO> result) {
        // 获取未上麦的 嘉宾/助理的列表
        LinkedList<GetRoomJoinsDataDTO> specialList = getSpecialUsers(roomId, speakArr);
        speakList.addAll(specialList);
        // 判断是否在线
        List<Integer> intes = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(speakList)) {
            for (GetRoomJoinsDataDTO single : speakList) {
                intes.add(single.getAccountId());
            }
        }
        if (CollectionUtils.isNotEmpty(intes)) {
            Map<String, Object> online = paasService.checkUserOnlineByChannel(room.getChannelId(), intes);
            speakList.removeIf(single ->
                    !((online.containsKey(single.getAccountId().toString()) && (int) online.get(single.getAccountId().toString()) > 0)
                            || com.vhall.component.plugin.common.constant.RoomConstant.HOST.equals(single.getRoleName())));
        }
        for (GetRoomJoinsDataDTO single : speakList) {
            GetUserListRspVO p = new GetUserListRspVO();
            BeanUtils.copyProperties(single, p);
            p.setIsKick(single.getIsKicked());
            result.add(p);
        }
    }


    /**
     * 超级高频调用接口  主要用于系统里面大量得查询      核心接口  inav/get  里面会调用  updateOrInsertRoomJoin
     *
     * @param roomId    房间id
     * @param accountId 账号id
     */
    @Override
    public RoomJoinsEntityDTO getRoomJoins(Integer accountId, String roomId) {
        // 先从缓存中获取参会信息
        RoomJoinsEntity roomJoins = roomCacheService.getCachedRoomJoins(roomId, accountId);
        if (Objects.isNull(roomJoins)) {
            return null;
        }
        return roomJoinsAssembler.joinsEntityToDTO(roomJoins);
    }

    @Override
    public void updateRoomJoins(RoomJoinsEntityDTO roomJoinInfo, String type, String status) {
        RoomJoinsEntity entity = new RoomJoinsEntity();
        roomJoinInfo.setDeviceType(Integer.parseInt(type));
        roomJoinInfo.setDeviceStatus(Integer.parseInt(status));
        BeanUtils.copyProperties(roomJoinInfo, entity);
        roomJoinsMapper.updateById(entity);
        // 缓存参会信息
        roomCacheService.cacheRoomJoins(entity.getJoinId());
    }

    @Override
    public void updateRoomJoinsById(RoomJoinsEntityDTO roomJoinInfo) {
        RoomJoinsEntity entity = new RoomJoinsEntity();
        BeanUtils.copyProperties(roomJoinInfo, entity);
        roomJoinsMapper.updateById(entity);
        // 缓存参会信息
        roomCacheService.cacheRoomJoins(entity.getJoinId());
    }

    @Override
    public RoomJoinsEntityDTO getCurrentJoinUserByThirdId(String roomId, Integer thirdId) {
        //根据房间id获取房间信息
        RoomsEntityDTO roomsEntityDTO = getRoomInfo(roomId);
        if (roomsEntityDTO == null) {
            //返回错误空房间

            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        //获取房间参会人员中的主持人
        RoomJoinsEntityDTO joinUser = getRoomJoinInfo(thirdId, roomId);
        if (joinUser == null) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        return joinUser;
    }

    @Override
    public Boolean batchBanned(String roomId, List<Integer> accountIdList, Integer status, Integer thirdPartyUserId) {
        RoomJoinsEntity roomJoinsEntity = new RoomJoinsEntity();
        RoomsEntityDTO room = getRoomInfo(roomId);
        if (room == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomJoinsEntity::getRoomId, roomId);
        if (CollectionUtils.isNotEmpty(accountIdList)) {
            where.in(RoomJoinsEntity::getAccountId, accountIdList);
        }
        List<RoomJoinsEntity> list = roomJoinsMapper.selectList(where);
        List<Integer> joinIds = list.stream().map(RoomJoinsEntity::getJoinId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(joinIds)) {
            return false;
        }
        roomJoinsEntity.setIsBanned(status);
        where.clear();
        where.in(RoomJoinsEntity::getJoinId, joinIds);
        int updCount = roomJoinsMapper.update(roomJoinsEntity, where);
        if (updCount == 0) {
            return false;
        }

        // 缓存禁言用户参与信息
        roomCacheService.cacheBannedJoin(roomId, accountIdList, Objects.nonNull(status) && status == 1);

        RoomJoinsEntityDTO currentJoinUser = getRoomJoinInfo(thirdPartyUserId, roomId);
        list.forEach(joinInfo -> {
            redisTemplate.delete(RedisKey.ROOM_JOIN_FLAG_BY_JID + joinInfo.getJoinId());
            redisTemplate.delete(RedisKey.ROOM_JOIN_FLAG + joinInfo.getAccountId() + "and" + roomId);
            redisTemplate.delete(RedisKey.ROOM_BANNED_NUM + roomId);
            JSONObject object = new JSONObject();
            object.put("type", status == 1 ? "disable" : "permit");
            object.put("room_join_id", currentJoinUser.getAccountId());
            object.put("target_id", joinInfo.getAccountId());
            object.put("nick_name", joinInfo.getNickname());
            String body = JsonUtil.toJsonString(object);
            paasService.sendCustomMessage(room.getChannelId(), currentJoinUser.getAccountId(), body, "service_custom");
        });
        return true;
    }

    @Override
    public Integer getBannedNum(String roomId) {
        Object cache = redisTemplate.opsForValue().get(RedisKey.ROOM_BANNED_NUM + roomId);
        int count;
        if (cache == null) {
            LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
            where.eq(RoomJoinsEntity::getRoomId, roomId)
                    .eq(RoomJoinsEntity::getIsBanned, 1);
            count = roomJoinsMapper.selectCount(where);
            if (count != 0) {
                redisTemplate.opsForValue().set(RedisKey.ROOM_BANNED_NUM + roomId, count);
            }
        } else {
            count = (int) cache;
        }
        return count;
    }

    @Override
    public Boolean batchKick(String roomId, List<Integer> accountIdList, Integer status, Integer thirdPartyUserId) {
        RoomJoinsEntity roomJoinsEntity = new RoomJoinsEntity();
        RoomsEntityDTO room = getRoomInfo(roomId);
        LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomJoinsEntity::getRoomId, roomId);
        if (CollectionUtils.isNotEmpty(accountIdList)) {
            where.in(RoomJoinsEntity::getAccountId, accountIdList);
        }
        List<RoomJoinsEntity> list = roomJoinsMapper.selectList(where);
        List<Integer> joinIds = list.stream().map(RoomJoinsEntity::getJoinId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(joinIds)) {
            return false;
        }
        //批量修改
        roomJoinsEntity.setIsKicked(status);
        where.clear();
        where.in(RoomJoinsEntity::getJoinId, joinIds);
        int updCount = roomJoinsMapper.update(roomJoinsEntity, where);
        if (updCount == 0) {
            return false;
        }

        // 缓存踢出用户参与信息
        roomCacheService.cacheKickedJoin(roomId, accountIdList, Objects.nonNull(status) && status == 1);

        RoomJoinsEntityDTO currentJoinUser = getRoomJoinInfo(thirdPartyUserId, roomId);
        list.forEach(joinInfo -> {
            redisTemplate.delete(RedisKey.ROOM_JOIN_FLAG_BY_JID + joinInfo.getJoinId());
            redisTemplate.delete(RedisKey.ROOM_JOIN_FLAG + joinInfo.getAccountId() + "and" + roomId);
            redisTemplate.delete(RedisKey.ROOM_BANNED_NUM + roomId);
            // 构建消息请求体
            JSONObject object = new JSONObject();
            object.put("type", status == 1 ? "room_kickout" : "room_kickout_cancel");
            object.put("room_join_id", currentJoinUser.getAccountId());
            object.put("target_id", joinInfo.getAccountId());
            object.put("nick_name", joinInfo.getNickname());
            object.put("push_time", LocalDateTime.now());
            String body = JsonUtil.toJsonString(object);
            paasService.sendMessage(room.getChannelId(), body, null, null, null, null);
        });
        return true;
    }

    @Override
    public BannedAndKickedListRspVO getBannedList(BannedKickedReqVO reqVO) {
        BannedAndKickedListRspVO result = new BannedAndKickedListRspVO();
        LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomJoinsEntity::getRoomId, reqVO.getRoomId())
                .eq(RoomJoinsEntity::getIsBanned, 1);
        Integer count = roomJoinsMapper.selectCount(where);
        where.last(RoomConstant.LIMIT + (reqVO.getPage() - 1) * reqVO.getPagesize() + "," + reqVO.getPagesize());

        List<RoomJoinsEntity> roomJoinsList = roomJoinsMapper.selectList(where);
        List<BannedAndKickedVO> list = new ArrayList<>();
        for (RoomJoinsEntity item : roomJoinsList) {
            BannedAndKickedVO vo = new BannedAndKickedVO();
            BeanUtils.copyProperties(item, vo);
            list.add(vo);
        }
        BeanUtils.copyProperties(reqVO, result);
        result.setTotal(count);
        result.setList(list);
        return result;
    }

    @Override
    public BannedKickedListRspVO getBannedCacheList(BannedKickedReqVO reqVO) {
        String roomId = reqVO.getRoomId();
        Integer page = reqVO.getPage();
        Integer pageSize = reqVO.getPagesize();

        CachePage<BannedKickedRspVO> cachePage = roomCacheService.listBannedCache(roomId, page, pageSize);
        BannedKickedListRspVO rspVO = new BannedKickedListRspVO();
        rspVO.setPage(page);
        rspVO.setPageSize(pageSize);
        rspVO.setTotal(cachePage.getTotal());
        rspVO.setList(cachePage.getList());
        return rspVO;
    }

    @Override
    public BannedAndKickedListRspVO getKickedList(BannedKickedReqVO reqVO) {
        BannedAndKickedListRspVO rspVO = new BannedAndKickedListRspVO();
        LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomJoinsEntity::getRoomId, reqVO.getRoomId())
                .eq(RoomJoinsEntity::getIsKicked, 1);
        Integer count = roomJoinsMapper.selectCount(where);
        where.last(RoomConstant.LIMIT + (reqVO.getPage() - 1) * reqVO.getPagesize() + "," + reqVO.getPagesize());
        List<RoomJoinsEntity> roomJoinsList = roomJoinsMapper.selectList(where);
        List<BannedAndKickedVO> list = new ArrayList<>();
        for (RoomJoinsEntity roomJoinsEntity : roomJoinsList) {
            BannedAndKickedVO getBannedListVO = new BannedAndKickedVO();
            BeanUtils.copyProperties(roomJoinsEntity, getBannedListVO);
            list.add(getBannedListVO);
        }
        BeanUtils.copyProperties(reqVO, rspVO);
        rspVO.setTotal(count);
        rspVO.setList(list);
        return rspVO;
    }

    @Override
    public BannedKickedListRspVO getKickedCacheList(BannedKickedReqVO reqVO) {
        String roomId = reqVO.getRoomId();
        Integer page = reqVO.getPage();
        Integer pageSize = reqVO.getPagesize();

        CachePage<BannedKickedRspVO> cachePage = roomCacheService.listKickedCache(roomId, page, pageSize);
        BannedKickedListRspVO rspVO = new BannedKickedListRspVO();
        rspVO.setPage(page);
        rspVO.setPageSize(pageSize);
        rspVO.setTotal(cachePage.getTotal());
        rspVO.setList(cachePage.getList());
        return rspVO;
    }

    @Override
    public BannedAndKickedListRspVO listBannedKicked(BannedKickedReqVO reqVO) {
        BannedAndKickedListRspVO result = new BannedAndKickedListRspVO();
        QueryWrapper<RoomJoinsEntity> where = new QueryWrapper<>();
        where.eq("room_id", reqVO.getRoomId());
        where.and(w -> w.eq("is_kicked", 1).or().eq("is_banned", 1));

        Integer count = roomJoinsMapper.selectCount(where);
        if (count > 0) {
            int limit = (reqVO.getPage() - 1) * reqVO.getPagesize();
            where.last(RoomConstant.LIMIT + limit + "," + reqVO.getPagesize());
            List<RoomJoinsEntity> roomJoinsList = roomJoinsMapper.selectList(where);

            List<BannedAndKickedVO> list = new ArrayList<>();

            for (RoomJoinsEntity entity : roomJoinsList) {
                BannedAndKickedVO bkv = new BannedAndKickedVO();
                BeanUtils.copyProperties(entity, bkv);
                list.add(bkv);
            }
            BeanUtils.copyProperties(reqVO, result);
            result.setTotal(count);
            result.setList(list);

        }
        result.setPagesize(reqVO.getPagesize());
        result.setPerPage(reqVO.getPagesize());
        result.setPageAll(calcPages(count, reqVO.getPagesize()));

        return result;
    }

    @Override
    public RoomJoinsEntityDTO queryRoomJoinsBySelectOne(QueryRoomJoinsBySelectOneReqVO reqVO) {
        // 根据room_id和role_name查询join数据。
        RoomJoinsEntityDTO dto = new RoomJoinsEntityDTO();
        LambdaQueryWrapper<RoomJoinsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StringUtils.isNotBlank(reqVO.getRoomId()), RoomJoinsEntity::getRoomId, reqVO.getRoomId());
        wrapper.eq(StringUtils.isNotBlank(reqVO.getRoleName()), RoomJoinsEntity::getRoleName, com.vhall.component.plugin.common.constant.RoomConstant.HOST);
        wrapper.last(RoomConstant.LIMIT_1);
        RoomJoinsEntity entity = roomJoinsMapper.selectOne(wrapper);
        if (entity == null) {
            return null;
        }
        BeanUtils.copyProperties(entity, dto);
        return dto;
    }


    @Override
    public RoomSupplyEntityDTO getRoomSupplyByIlId(Integer ilId) {
        RoomSupplyEntityDTO dto = new RoomSupplyEntityDTO();
        LambdaQueryWrapper<RoomSupplyEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomSupplyEntity::getIlId, ilId);
        RoomSupplyEntity entity = supplyMapper.selectOne(wrapper);
        if (entity == null) {
            return null;
        }
        BeanUtils.copyProperties(entity, dto);
        return dto;
    }

    @Override
    public RoomJoinsEntityDTO updateOrInsertRoomJoin(RoomsEntityDTO room, String profilePhoto, Integer accountId, Integer roleName, String username, String nickname) {
        String roomId = room.getRoomId();
        RoomJoinsEntityDTO join = getRoomJoins(accountId, roomId);
        RoomJoinsEntity entity = new RoomJoinsEntity();
        LocalDateTime now = LocalDateTime.now();
        if (join == null) {
            String avatar = StringUtils.isEmpty(profilePhoto) ? defaultAvatar : profilePhoto;
            join = new RoomJoinsEntityDTO();
            join.setRoomId(roomId);
            join.setAccountId(Integer.parseInt(String.valueOf(accountId)));
            join.setUsername(username);
            join.setNickname(nickname);
            join.setAvatar(avatar);
            join.setRoleName(String.valueOf(roleName));
            join.setCreatedAt(now);
            join.setUpdatedAt(now);
            BeanUtils.copyProperties(join, entity);
            if (Objects.nonNull(room.getStartTime()) && room.getStartTime().isAfter(now)) {
                entity.setPreLive(RoomJoinsPreLiveEnum.PRE_LIVE.getValue());
                entity.setFirstPreLiveTime(now);
            }else{
                entity.setPreLive(RoomJoinsPreLiveEnum.AFTER_LIVE.getValue());
            }
            entity.setUserJoinCount(1);
            roomJoinsMapper.insert(entity);
        } else {
            join.setUsername(username);
            join.setNickname(nickname);
            join.setRoleName(String.valueOf(roleName));
            BeanUtils.copyProperties(join, entity);
            entity.setUpdatedAt(now);
//            由于环境中,直播状态对外显示是和直播时间一起计算得出的,是无法直接作为标识使用,所以只使用开始直播时间作为唯一计算条件
            if (Objects.nonNull(room.getStartTime())
                    && room.getStartTime().isAfter(now)
                    && Objects.equals(Optional.ofNullable(join.getPreLive()).orElse(RoomJoinsPreLiveEnum.AFTER_LIVE.getValue()),RoomJoinsPreLiveEnum.AFTER_LIVE.getValue())) {
                entity.setPreLive(RoomJoinsPreLiveEnum.PRE_LIVE.getValue());
                entity.setFirstPreLiveTime(now);
            }
            entity.setUserJoinCount(Optional.ofNullable(entity.getUserJoinCount()).orElse(1)+1);
            roomJoinsMapper.updateById(entity);
        }
        //  代码优化 - 对缓存数据进行更新
        roomCacheService.cacheRoomJoins(entity);
        return join;
    }

    @Override
    public Integer updateLotteryWinner(RoomJoinsEntityDTO roomJoinsEntityDTO, String roomId, List<Integer> accountIds) {
        LambdaUpdateWrapper<RoomJoinsEntity> wrapper = Wrappers.<RoomJoinsEntity>lambdaUpdate()
                .set(RoomJoinsEntity::getIsLotteryWinner, roomJoinsEntityDTO.getIsLotteryWinner())
                .set(RoomJoinsEntity::getUpdatedAt, LocalDateTime.now()).eq(RoomJoinsEntity::getRoomId, roomId)
                .in(RoomJoinsEntity::getAccountId, accountIds);

        int result = roomJoinsMapper.update(null, wrapper);
        // 若更新到数据，则重新缓存参会信息
        if (result > 0) {
            // 重新缓存参会信息
            roomCacheService.cacheRoomJoins(roomId, accountIds);
        }
        return result;
    }

    @Override
    public int updateIsAnsweredVoteByJoinId(String roomId, String thirdPartyUserId) {
        LambdaUpdateWrapper<RoomJoinsEntity> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(RoomJoinsEntity::getRoomId, roomId).eq(RoomJoinsEntity::getAccountId, thirdPartyUserId)
                .eq(RoomJoinsEntity::getIsAnsweredVote, 0);

        RoomJoinsEntity updEntity = new RoomJoinsEntity();
        updEntity.setIsAnsweredVote(1);
        updEntity.setUpdatedAt(LocalDateTime.now());

        int count = roomJoinsMapper.update(updEntity, updateWrapper);
        // 若更新到数据，则重新缓存参会信息
        if (count > 0) {
            roomCacheService.cacheRoomJoins(roomId, Integer.parseInt(thirdPartyUserId));
        }
        return count;
    }

    @Override
    public void updateIsSignedByJoinId(String roomId, String thirdPartyUserId) {
        LambdaUpdateWrapper<RoomJoinsEntity> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(RoomJoinsEntity::getRoomId, roomId).eq(RoomJoinsEntity::getAccountId, thirdPartyUserId)
                .eq(RoomJoinsEntity::getIsSigned, 0);

        RoomJoinsEntity updEntity = new RoomJoinsEntity();
        updEntity.setIsSigned(1);
        updEntity.setUpdatedAt(LocalDateTime.now());

        // 更新签到状态
        // 若更新到数据，则重新缓存参会信息
        if (roomJoinsMapper.update(updEntity, updateWrapper) > 0) {
            roomCacheService.cacheRoomJoins(roomId, Integer.parseInt(thirdPartyUserId));
        }
    }

    @Override
    public RoomJoinsEntityDTO getRoomJoinsByRoomIdAndThirdId(String roomId, Integer thirdPartyUserId) {
        RoomsEntityDTO roomInfo = getRoomInfo(roomId);
        if (Objects.isNull(roomInfo)) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (Objects.isNull(thirdPartyUserId) || thirdPartyUserId <= 0) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        return getRoomJoinInfo(thirdPartyUserId, roomId);
    }

    @Override
    public RoomsEntityDTO getRoomsEntityInfo(String roomId) {
        RoomsEntityDTO roomsEntityDTO = new RoomsEntityDTO();
        RoomsEntity roomsEntity = roomMapper.selectOne(Wrappers.<RoomsEntity>lambdaQuery()
                .eq(RoomsEntity::getRoomId, roomId).last(LIMIT_1));
        if (roomsEntity == null) {
            return null;
        }
        BeanUtils.copyProperties(roomsEntity, roomsEntityDTO);
        return roomsEntityDTO;
    }

    @Override
    public Integer getCountByIlidAndRecordId(String ilId, String recordId) {
        return roomMapper.selectCount(Wrappers.<RoomsEntity>lambdaQuery()
                .eq(RoomsEntity::getIlId, ilId)
                .eq(RoomsEntity::getRecordId, recordId));
    }

    @Override
    public Integer updateByIl(RoomsEntityDTO dto) {

        if (StringUtils.isBlank(dto.getRoomId()) && dto.getIlId() == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM_INFO);
        }

        if (StringUtils.isBlank(dto.getRoomId()) || dto.getIlId() == null) {
            LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
            if (StringUtils.isBlank(dto.getRoomId())) {
                wrapper.eq(RoomsEntity::getIlId, dto.getIlId());
            } else if (dto.getIlId() == null) {
                wrapper.eq(RoomsEntity::getRoomId, dto.getRoomId());
            }
            RoomsEntity entity = roomMapper.selectOne(wrapper);
            dto.setIlId(entity.getIlId());
            dto.setRoomId(entity.getRoomId());
        }


        RoomsEntity roomsEntity = new RoomsEntity();
        BeanUtils.copyProperties(dto, roomsEntity);
        redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + dto.getRoomId());
        redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + dto.getIlId());
        return roomMapper.update(roomsEntity, Wrappers.<RoomsEntity>lambdaQuery()
                .eq(RoomsEntity::getIlId, roomsEntity.getIlId()));
    }

    @Override
    public List<RoomRspVO> selectRoomList(List<Integer> ilIdlist) {
        return roomMapper.selectRoomList(ilIdlist);
    }

    @Override
    public void updateLikeById(RoomsEntityDTO rooms) {
        RoomsEntity roomsEntity = new RoomsEntity();
        BeanUtils.copyProperties(rooms, roomsEntity);
        roomMapper.updateById(roomsEntity);
        redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + rooms.getRoomId());
        redisTemplate.delete(RedisKey.ROOM_INFO_BY_ROOM_ID + rooms.getIlId());
    }


    @Override
    public List<RoomsEntityDTO> getRoomsInfoByRoomIds(String roomIds) {
        if (StringUtils.isBlank(roomIds)) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        ArrayList<RoomsEntityDTO> reds = new ArrayList<>();
        List list = JSON.parseObject(roomIds, List.class);
        for (Object o : list) {
            reds.add(getRoomInfo(o.toString()));
        }
        return reds;
    }

    @Override
    public Map<String, Object> getRoomsEntityByRebroadcastList(ListReqVo reqVo) {
        int page = reqVo.getCurrPage() == null ? 1 : reqVo.getCurrPage();
        int pageSize = reqVo.getPageSize() == null ? 20 : reqVo.getPageSize();
        RoomsEntityDTO roomInfo = getRoomInfo(reqVo.getRoomId());
        if (roomInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        LambdaQueryWrapper<RoomsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomsEntity::getStatus, 1);
        wrapper.eq(roomInfo.getAccountId() != null, RoomsEntity::getAccountId, roomInfo.getAccountId());
        wrapper.ne(RoomsEntity::getRoomId, reqVo.getRoomId());
        RoomsEntityDTO source = null;
        if (reqVo.getSourceRoomId() != null) {
            wrapper.ne(RoomsEntity::getRoomId, reqVo.getSourceRoomId());
            source = getRoomsEntityInfo(reqVo.getSourceRoomId());
        }
        if (reqVo.getSubject() != null) {
            wrapper.like(RoomsEntity::getSubject, reqVo.getSubject());
        }
        Integer count = roomMapper.selectCount(wrapper);
        Integer totalPage = count / page;
        int currStar = page == 1 ? 0 : pageSize * (page - 1);
        wrapper.orderByDesc(RoomsEntity::getCreatedAt)
                .last(RoomConstant.LIMIT + currStar + "," + pageSize);
        List<RoomsEntity> lists = roomMapper.selectList(wrapper);
        ArrayList<RoomToReboadcastListRspVo> roomDtoList = new ArrayList<>();
        lists.forEach(r -> {
            RoomToReboadcastListRspVo list = new RoomToReboadcastListRspVo();
            BeanUtils.copyProperties(r, list);
            roomDtoList.add(list);
        });
        if (source != null && page == 1) {
            RoomToReboadcastListRspVo roomDto = new RoomToReboadcastListRspVo();
            BeanUtils.copyProperties(source, roomDto);
            roomDtoList.add(roomDto);
        }
        roomDtoList.forEach(r -> {
            r.setIsStream(0);
            if (StringUtils.isNotBlank(reqVo.getSourceRoomId()) && reqVo.getSourceRoomId().equals(r.getRoomId())) {
                r.setIsStream(1);
            }
        });
        HashMap<String, Object> map = new HashMap<>(4);
        map.put("list", roomDtoList);
        map.put("total", count);
        map.put("total_page", totalPage);
        map.put("page", page);
        return map;
    }

    @Override
    public RoomExtendsDTO getRoomExtendsByRoomId(String roomId) {
        LambdaQueryWrapper<RoomExtendsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomExtendsEntity::getRoomId, roomId);
        wrapper.orderByDesc(RoomExtendsEntity::getCreatedAt);
        wrapper.last(RoomConstant.LIMIT_1);
        RoomExtendsEntity entity = roomExtendsMapper.selectOne(wrapper);
        if (entity == null) {
            return null;
        }
        RoomExtendsDTO roomExtendsDTO = new RoomExtendsDTO();
        BeanUtils.copyProperties(entity, roomExtendsDTO);
        return roomExtendsDTO;
    }

    @Override
    public List<RoomJoinsEntityDTO> getRoomJoinsList(QueryRoomJoinsReqVO reqVO) {
        LambdaQueryWrapper<RoomJoinsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(!Objects.isNull(reqVO.getIsLotteryWinner()), RoomJoinsEntity::getIsLotteryWinner, reqVO.getIsLotteryWinner())
                .eq(!Objects.isNull(reqVO.getAccountId()), RoomJoinsEntity::getAccountId, reqVO.getAccountId())
                .eq(StringUtils.isNotBlank(reqVO.getRoomId()), RoomJoinsEntity::getRoomId, reqVO.getRoomId())
                .eq(!Objects.isNull(reqVO.getIsSigned()), RoomJoinsEntity::getIsSigned, reqVO.getIsSigned())
                .eq(!Objects.isNull(reqVO.getIsAnsweredQuestionnaire()), RoomJoinsEntity::getIsAnsweredQuestionnaire, reqVO.getIsAnsweredQuestionnaire())
                .isNull(RoomJoinsEntity::getDeletedAt);
        if (StringUtils.isNotBlank(reqVO.getAccountIds())) {
            wrapper.in(RoomJoinsEntity::getAccountId,
                    Arrays.stream(reqVO.getAccountIds().split(","))
                            .map(Integer::parseInt).collect(Collectors.toList()));
        }
        if (StringUtils.isNotBlank(reqVO.getNickname()) || StringUtils.isNotBlank(reqVO.getUsername())) {

            if (StringUtils.isNotBlank(reqVO.getNickname()) && StringUtils.isNotBlank(reqVO.getUsername())) {
                wrapper.and(x -> x.eq(RoomJoinsEntity::getNickname, reqVO.getNickname()).or().eq(RoomJoinsEntity::getUsername, reqVO.getUsername()));

            } else {
                String nickname = StringUtils.isNotBlank(reqVO.getNickname()) ? reqVO.getNickname() : reqVO.getUsername();
                wrapper.and(x -> x.eq(RoomJoinsEntity::getNickname, nickname).or().eq(RoomJoinsEntity::getUsername, nickname));
            }

        }
        if (StringUtils.isNotBlank(reqVO.getRoleName())) {
            switch (reqVO.getRoleNameOperate()) {
                case ">":
                    wrapper.gt(RoomJoinsEntity::getRoleName, reqVO.getRoleName());
                    break;
                case "<":
                    wrapper.lt(RoomJoinsEntity::getRoleName, reqVO.getRoleName());
                    break;
                case "=":
                    wrapper.eq(RoomJoinsEntity::getRoleName, reqVO.getRoleName());
                    break;
                case "<=":
                    wrapper.le(RoomJoinsEntity::getRoleName, reqVO.getRoleName());
                    break;
                case ">=":
                    wrapper.ge(RoomJoinsEntity::getRoleName, reqVO.getRoleName());
                    break;
                default:
                    break;

            }
        }
        List<RoomJoinsEntity> roomJoinsList = roomJoinsMapper.selectList(wrapper);
        return roomJoinsList.stream().map(roomJoinsEntity -> {
            RoomJoinsEntityDTO roomJoinsEntityDTO = new RoomJoinsEntityDTO();
            BeanUtils.copyProperties(roomJoinsEntity, roomJoinsEntityDTO);
            return roomJoinsEntityDTO;
        }).collect(Collectors.toList());
    }


    @Override
    public Map<Integer, RoomJoinsEntityDTO> getRoomInfoBySenderIds(String roomId, String senderIds) {
        List<String> senderId = JSON.parseObject(senderIds, List.class);
        LambdaQueryWrapper<RoomJoinsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoomJoinsEntity::getRoomId, roomId)
                .in(RoomJoinsEntity::getAccountId, senderId)
                .isNull(RoomJoinsEntity::getDeletedAt);
        List<RoomJoinsEntity> roomJoinsList = roomJoinsMapper.selectList(wrapper);
        if (roomJoinsList == null) {
            return Collections.emptyMap();
        }
        //将accountId当做Map的key，对应的数据为value
        Map<Integer, RoomJoinsEntityDTO> map = new HashMap<>(16);
        for (RoomJoinsEntity roomJoins : roomJoinsList) {
            RoomJoinsEntityDTO roomJoinsDTO = new RoomJoinsEntityDTO();
            BeanUtils.copyProperties(roomJoins, roomJoinsDTO);
            map.put(roomJoins.getAccountId(), roomJoinsDTO);
        }
        return map;
    }


    @Override
    public List<RoomJoinsEntityDTO> getRoomInfoByAccountIds(String roomId, String accountIds) {
        Set accountIdSet = JSON.parseObject(accountIds, Set.class);
        if (CollectionUtils.isEmpty(accountIdSet)) {
            return Collections.emptyList();
        }
        // 缓存方式获取参会信息
        List<String> accountList = new ArrayList<>();
        accountList.addAll(accountIdSet);


        LambdaQueryWrapper<RoomJoinsEntity> queryWrapper = Wrappers.lambdaQuery();
        //查询主库
        queryWrapper.first("/*FORCE_MASTER*/");
        queryWrapper.eq(RoomJoinsEntity::getRoomId, roomId);
        queryWrapper.in(RoomJoinsEntity::getAccountId, accountList);


        List<RoomJoinsEntity> roomJoinsEntities = roomJoinsMapper.selectList(queryWrapper);
        return roomJoinsAssembler.joinsEntitiesToDTOList(roomJoinsEntities);
    }

    @Override
    public RoomsEntityDTO getRoomInfoById(Integer ilId) {
        return getRoomInfoByIlId(String.valueOf(ilId));
    }

    @Override
    public RoomJoinsEntityDTO getHostUserInfoByRoomId(String roomId) {
        RoomJoinsEntity roomJoinsEntity = roomCacheService.getCachedHostRoomJoin(roomId);
        if (Objects.nonNull(roomJoinsEntity)) {
            LambdaQueryWrapper<RoomJoinsEntity> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(RoomJoinsEntity::getRoomId, roomId)
                    .eq(RoomJoinsEntity::getRoleName, 1)
                    .orderByDesc(RoomJoinsEntity::getJoinId)
                    .last(" limit 1 ");
            roomJoinsEntity = roomJoinsMapper.selectOne(wrapper);
            if (Objects.nonNull(roomJoinsEntity)) {
                roomCacheService.cacheHostRoomJoin(roomJoinsEntity);
            }
        }
        return roomJoinsAssembler.joinsEntityToDTO(roomJoinsEntity);
    }

    @Override
    public IndexDto getCount(String beginTime) {
        return getCount(beginTime,null);
    }

    @Override
    public IndexDto getCount(String beginTime, String orgCode) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT);
        LocalDateTime time = LocalDateTime.parse(beginTime, df);
        LocalDateTime today = LocalDate.now().atStartOfDay();
        LambdaQueryWrapper<RoomsEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.ne(RoomsEntity::getStatus,RoomStatusEnum.TO_BE_BROADCAST.getStatus())
        .eq(RoomsEntity::getLiveRormal,LiveRormalEnum.OFFICIAL_LIVE.getValue());
        Integer total = roomMapper.selectCount(queryWrapper);
        queryWrapper.clear();
        queryWrapper.ne(RoomsEntity::getStatus,RoomStatusEnum.TO_BE_BROADCAST.getStatus())
                .eq(RoomsEntity::getLiveRormal,LiveRormalEnum.OFFICIAL_LIVE.getValue())
                .le(RoomsEntity::getStartTime,today.plusDays(1));
        Integer day = roomMapper.selectCount(queryWrapper.ge(RoomsEntity::getStartTime, time));
        queryWrapper.clear();
        queryWrapper.ne(RoomsEntity::getStatus,RoomStatusEnum.TO_BE_BROADCAST.getStatus())
                .eq(RoomsEntity::getLiveRormal,LiveRormalEnum.OFFICIAL_LIVE.getValue())
                .le(RoomsEntity::getStartTime,today);
        Integer week = roomMapper.selectCount(queryWrapper.ge(RoomsEntity::getStartTime, time.plusDays(-1 * SelectTimeIntervalOptionsEnum.PAST_7_DAYS.getDay())));
        queryWrapper.clear();
        queryWrapper.ne(RoomsEntity::getStatus,RoomStatusEnum.TO_BE_BROADCAST.getStatus())
                .eq(RoomsEntity::getLiveRormal,LiveRormalEnum.OFFICIAL_LIVE.getValue())
                .le(RoomsEntity::getStartTime,today);
        Integer month = roomMapper.selectCount(queryWrapper.ge(RoomsEntity::getStartTime, time.plusDays(-1 * SelectTimeIntervalOptionsEnum.PAST_30_DAYS.getDay())));
        queryWrapper.clear();
        queryWrapper.ne(RoomsEntity::getStatus,RoomStatusEnum.TO_BE_BROADCAST.getStatus())
                .eq(RoomsEntity::getLiveRormal,LiveRormalEnum.OFFICIAL_LIVE.getValue())
                .le(RoomsEntity::getStartTime,today);
        Integer year = roomMapper.selectCount(queryWrapper.ge(RoomsEntity::getStartTime, time.minusYears(1L)));
        IndexDto indexDto = new IndexDto();
        indexDto.setTotal(total);
        indexDto.setDay(day);
        indexDto.setWeek(week);
        indexDto.setMonth(month);
        indexDto.setYear(year);
        return indexDto;
    }

    @Override
    public Integer sumMessageTotal(Integer ilId, LocalDateTime beginTime, LocalDateTime endTime) {
        RoomsEntityDTO roomsEntityDTO = getRoomInfoByIlId(String.valueOf(ilId));
        return paasService.getMessageCount(roomsEntityDTO.getChannelId(), DateUtil.format(beginTime, DatePattern.NORM_DATETIME_PATTERN),
                DateUtil.format(endTime, DatePattern.NORM_DATETIME_PATTERN));
    }

    @Override
    public RoomJoinsEntity getAnchorInfo(String roomId, Integer accountId) {
        QueryWrapper<RoomJoinsEntity> where = new QueryWrapper<>();
        where.eq("room_id", roomId);
        where.eq("role_name", "1");
        where.last(LIMIT_1);
        return roomJoinsMapper.selectOne(where);
    }

    @Override
    public int countRoomForAdminExport(AdminExportRoomQueryCondition condition) {
        QueryWrapper<Object> wrapper = new QueryWrapper<>();
        if (Objects.nonNull(condition)) {
            wrapper.ge(Objects.nonNull(condition.getStartTime()), "rooms.created_at", condition.getStartTime());
            wrapper.eq(Objects.nonNull(condition.getOptionStatus()), "rooms.status", condition.getOptionStatus());
            if (Objects.nonNull(condition.getEndTime())) {
                wrapper.lt("rooms.created_at", condition.getEndTime().plusDays(1));
            }
            String keyword = condition.getKeyword();
            // 模糊查询支持，房间id、房间名称、创建人名称
            wrapper.and(StringUtils.isNotEmpty(keyword),
                    w -> w.like("rooms.il_id", keyword).or().like("rooms.subject", keyword).or()
                            .like("account.nickname", keyword));
        }
        return roomMapper.countRoomForAdmin(wrapper);
    }

    @Override
    public Map<String, Object> getRoomWarmInfo(Integer ilId) {
        return roomCacheService.getCachedRoomWarmInfo(getRoomInfoById(ilId));
    }

    @Override
    public String getDefaultWatermarkTemplateId() {
        Object cacheData = redisTemplate.opsForValue().get(RedisKey.DEFAULT_WATERMARK_TEMPLATE_KEY);
        Integer configValue;
        if (Objects.isNull(cacheData)) {
            RoomConfig roomConfig = roomConfigMapper.selectOne(Wrappers.<RoomConfig>lambdaQuery().eq(RoomConfig::getConfigKey, com.vhall.component.plugin.common.constant.RoomConstant.DEFAULT_WATERMARK_TEMPLATE));
            configValue = Optional.ofNullable(roomConfig).orElse(new RoomConfig()).getConfigValue();
            configValue = Optional.ofNullable(configValue).orElse(0);
            redisTemplate.opsForValue().set(RedisKey.DEFAULT_WATERMARK_TEMPLATE_KEY, configValue.toString());
        } else {
            return cacheData.toString();
        }
        return String.valueOf(configValue);
    }

    @Override
    public void setDefaultWatermarkTemplateId(Integer watermarkTemplateId) {
        RoomConfig roomConfig = roomConfigMapper.selectOne(Wrappers.<RoomConfig>lambdaQuery()
                .eq(RoomConfig::getConfigKey, com.vhall.component.plugin.common.constant.RoomConstant.DEFAULT_WATERMARK_TEMPLATE));
        if (Objects.isNull(roomConfig)) {
            roomConfig = new RoomConfig();
            roomConfig.setRoomId("");
            roomConfig.setConfigKey(com.vhall.component.plugin.common.constant.RoomConstant.DEFAULT_WATERMARK_TEMPLATE);
            roomConfig.setConfigValue(watermarkTemplateId);
            roomConfig.setIlId(0);
            LocalDateTime now = LocalDateTime.now();
            roomConfig.setUpdatedAt(now);
            roomConfig.setAccountId(0);
            roomConfig.setCreatedAt(now);
            roomConfigMapper.insert(roomConfig);
            redisTemplate.opsForValue().set(RedisKey.DEFAULT_WATERMARK_TEMPLATE_KEY, watermarkTemplateId.toString(), 1, TimeUnit.DAYS);
        } else {
            roomConfig.setConfigKey(com.vhall.component.plugin.common.constant.RoomConstant.DEFAULT_WATERMARK_TEMPLATE);
            roomConfig.setConfigValue(watermarkTemplateId);
            LocalDateTime now = LocalDateTime.now();
            roomConfig.setUpdatedAt(now);
            roomConfigMapper.updateById(roomConfig);
            redisTemplate.opsForValue().set(RedisKey.DEFAULT_WATERMARK_TEMPLATE_KEY, watermarkTemplateId.toString(), 1, TimeUnit.DAYS);
        }
    }

    @Override
    public void clearRoomWatermark(String tempId) {
        List<RoomsEntity> roomsEntities = roomMapper.selectList(Wrappers.<RoomsEntity>lambdaQuery().eq(StringUtils.isNotBlank(tempId), RoomsEntity::getWatermarkTempId, tempId));
        if (!roomsEntities.isEmpty()) {
            UpdateWrapper<RoomsEntity> update = new UpdateWrapper<>();
            update.eq("watermark_temp_id", Integer.parseInt(tempId));
            update.set("watermark_temp_id", 0);
            roomMapper.update(null, update);
            Map<String, Object> param;
            StringJoiner roomIds = new StringJoiner(",");
            for (RoomsEntity roomsEntity : roomsEntities) {
                param = new HashMap<>(8);
                param.put("room_id", roomsEntity.getRoomId());
                param.put("watermark_id", 0);
                paasService.setStreamWatermark(param);
                roomIds.add(roomsEntity.getRoomId());
            }
            log.info("删除房间水印,发送请求给 paas 平台 清理房间水印,房间 id:{}", roomIds);
        }
    }

    @Override
    public Long getVirtualPV(Integer ilId) {
        QueryWrapper<RoomStatsExpansion> queryWrapper = Wrappers.query();
        queryWrapper.eq("il_id", ilId);
        Integer selectCount = roomStatsExpansionMapper.selectCount(queryWrapper);
        if (selectCount > 0) {
            queryWrapper.select("SUM(expansion_number) as total");
            List<Map<String, Object>> mapList = roomStatsExpansionMapper.selectMaps(queryWrapper);
            Map<String, Object> objectMap = mapList.get(0);
            Object total = objectMap.get("total");
            if (total == null) {
                total = 0;
            }
            List<Integer> idList = new ArrayList<>();
            idList.add(ilId);
            UserParamVO paramVO = new UserParamVO();
            paramVO.setIlIdList(idList);
            UserBasicStatisticsRspVO live = accountForDataMapper.getBasicStatisticsInfo(paramVO);
            UserBasicStatisticsRspVO rec = accountForDataMapper.getVodBasicStatisticsInfo(paramVO);
            Integer cacheLiveExternalChannelViewCount = externalLiveStatsService.getCacheLiveExternalChannelViewCount(ilId);
            Long countSum = 0L;
            if (live != null) {
                countSum += live.getPvCount();
            }
            if (rec != null) {
                countSum += rec.getPvCount();
            }
            countSum += cacheLiveExternalChannelViewCount;
            return Long.parseLong(String.valueOf(total)) + countSum;
        } else {
            return 0L;
        }
    }

    @Override
    public Map<Integer, Long> getVirtualPV(List<Integer> ilIds) {
        QueryWrapper<RoomStatsExpansion> queryWrapper = Wrappers.query();
        queryWrapper.in("il_id", ilIds);
        Integer selectCount = roomStatsExpansionMapper.selectCount(queryWrapper);
        if (selectCount > 0) {
            queryWrapper.select("il_id,SUM(expansion_number) as total");
            queryWrapper.groupBy(" il_id");
            List<Map<String, Object>> mapList = roomStatsExpansionMapper.selectMaps(queryWrapper);
            Map<Integer, Long> m = new HashMap<>();
            mapList.forEach(map -> {
                m.put(Integer.parseInt(String.valueOf(map.get("il_id"))),
                        Long.parseLong(String.valueOf(map.get("total"))));
            });
            return m;
        }
        return new HashMap<>();
    }

    @Override
    public Integer getShowRoomStatus(RoomsEntityDTO room) {
        Optional.ofNullable(room).orElseThrow(()->new BusinessException(BizErrorCode.EMPTY_ROOM));
        Boolean changeRoomStatus = checkChangeRoomStatus(room);
        if(changeRoomStatus){
            return RoomStatusEnum.TO_BE_BROADCAST.getStatus();
        }
        return room.getStatus();
    }
    @Override
    public Integer getShowRoomStatus(RoomsEntity room) {
        Optional.ofNullable(room).orElseThrow(()->new BusinessException(BizErrorCode.EMPTY_ROOM));
        RoomsEntityDTO roomsEntityDTO = new RoomsEntityDTO();
        BeanUtil.copyProperties(room, roomsEntityDTO);
        return getShowRoomStatus(roomsEntityDTO);
    }



    @Override
    public List<ThirdUserVO> getCacheRoomAnchorInfoList(Integer ilId) {
        List<ThirdUserVO> anchorRoomInfo;
        String key = RedisKey.ROOM_ANCHOR_LIST_CACHE+ilId;
        if (redisTemplate.hasKey(key)) {
            anchorRoomInfo = (List<ThirdUserVO>) redisTemplate.opsForValue().get(key);
        }else{
            anchorRoomInfo = getAnchorRoomInfo(ilId);
            try{
                anchorRoomInfo = buildInvestmentAdvisorTeamInfoBatch(anchorRoomInfo);
                redisTemplate.opsForValue().set(key,anchorRoomInfo,1,TimeUnit.HOURS);
            }catch (Exception e){
                log.error("构建投顾信息出现异常,防止影响主流程业务",e);
            }
        }
        return anchorRoomInfo;
    }
    /**
     * 批量进行投顾 IP ,投顾团队相关信息的构建
     * @param anchorRoomInfo
     * @return
     */
    private List<ThirdUserVO> buildInvestmentAdvisorTeamInfoBatch(List<ThirdUserVO> anchorRoomInfo) {
        List<ThirdUserVO> result = new ArrayList<>();
        if (CollUtil.isNotEmpty(anchorRoomInfo)) {
            ThirdUserVO thirdUserVO = anchorRoomInfo.get(0);
//            非内部员工不做投顾信息判定
            if (Objects.equals(ThirdUserTypeEnum.NO_STAFF.getValue(),thirdUserVO.getUserType())) {
                return anchorRoomInfo;
            }
            for (ThirdUserVO userVO : anchorRoomInfo) {
                result.add(buildInvestmentAdvisorTeamInfo(userVO));
            }
        }
        return result;
    }
    /**
     * 进行投顾 IP ,投顾团队相关信息的构建
     * @param userVO
     * @return
     */
    private ThirdUserVO buildInvestmentAdvisorTeamInfo(ThirdUserVO userVO) {
//        主播的用户 编码
        String userCode = userVO.getUserCode();
        String key = RedisKey.GUO_SEN_STAFF_USER_INFO+userCode;
        if (redisTemplate.hasKey(key)) {
            userVO = (ThirdUserVO) redisTemplate.opsForValue().get(key);
        }else{
            LambdaQueryWrapper<GuosenStaffEntity> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper
                    .eq(GuosenStaffEntity::getNotesid,userCode)
                    .last("limit 1");
            GuosenStaffEntity guosenStaffEntity = guosenStaffService.getOne(queryWrapper);
            if (Objects.nonNull(guosenStaffEntity)) {
                if (Objects.equals(guosenStaffEntity.getZyzg(),thirdPartyProperties.getTgh().getZyzg())) {
                    GetTghInfoDTO dto = new GetTghInfoDTO();
                    dto.setNotesid(userCode);
                    GuoxinInvestmentAdvisorTeamDTO advisorTeamDTO = guoXinService.getGuoxinInvestmentAdvisorTeamDTO(dto);
                    BeanUtil.copyProperties(advisorTeamDTO,userVO);
                }
            }
            redisTemplate.opsForValue().set(key,userVO,1,TimeUnit.HOURS);
        }
        return userVO;
    }
    private List<ThirdUserVO> getAnchorRoomInfo(Integer ilId) {
        List<ThirdUserVO> result ;
        LambdaQueryWrapper<AnchorRoomRelationEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AnchorRoomRelationEntity::getIlId,ilId)
                .orderByAsc(AnchorRoomRelationEntity::getId);
        List<AnchorRoomRelationEntity> list = anchorRoomRelationService.list(queryWrapper);
        result = Optional.ofNullable(list.stream().map(data -> {
            ThirdUserVO temp = new ThirdUserVO();
            temp.setName(data.getUserName());
            temp.setUserCode(data.getUserCode());
            temp.setUserType(data.getUserType());
            temp.setOrgCode(data.getOrgCode());
            temp.setOrgName(data.getOrgName());
            temp.setAdvisorLicenseNo(data.getAdvisorLicenseNo());
            return temp;
        }).collect(Collectors.toList())).orElse(new ArrayList<>());
        return result;
    }
    @NotNull
    private Boolean checkChangeRoomStatus(RoomsEntityDTO room) {
//      测试直播房间
        if (Objects.equals(LiveRormalEnum.TEST_LIVE.getValue(), room.getLiveRormal())) {
            return false;
        }
        LocalDateTime startTime = room.getStartTime();
        LocalDateTime now = LocalDateTime.now();
//        直播时间已过
        if (startTime.isBefore(now)) {
            return false;
        }
        Token token = TokenThreadLocal.getToken();
        if (Objects.nonNull(token)) {
            Integer accountId = room.getAccountId();
//            主持人获取的直播状态为正常直播状态
            if (Objects.equals(accountId,token.getAccountId())) {
                return false;
            }
//            助理嘉宾,访问的时候返回正常的直播状态
            if (Objects.equals(RoleNameEnum.ASSISTANT.getValue(),token.getRoleName())
                    || Objects.equals(RoleNameEnum.GUEST.getValue(),token.getRoleName())
            ) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取上麦用户 [已排序的列表, 主持人第一位 - 其他上麦用户]
     *
     * @param roomId 房间Id
     * @return 返回上麦用户列表
     */
    private LinkedList<GetRoomJoinsDataDTO> getSpeakUsers(String roomId) {

        // 缓存读取已上线列表
        Map<Object, Object> speakerMap = getSpeakerList(roomId);
        //返回上麦用户列表集合
        LinkedList<GetRoomJoinsDataDTO> result = new LinkedList<>();

        if (speakerMap.size() != 0) {
            // 获取所有的上麦用户
            Map<Integer, GetSpeakerUsersDTO> users = speakerMap.values().stream().map(object -> {
                // 把json字符串转换成GetSpeakerUsersDTO对象
                String text = JSON.parse(String.valueOf(object)).toString();
                return JSON.parseObject(text, GetSpeakerUsersDTO.class);
            }).collect(Collectors.toMap(GetSpeakerUsersDTO::getAccountId, getSpeakerUsersDTO -> getSpeakerUsersDTO));
            // 得到所有上麦用户中所有的account_id
            List<Integer> accountIdList = users.values()
                    .stream()
                    .map(GetSpeakerUsersDTO::getAccountId)
                    .collect(Collectors.toList());
            accountIdList = accountIdList.stream().distinct().collect(Collectors.toList());
            LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
            where.eq(RoomJoinsEntity::getRoomId, roomId)
                    .in(RoomJoinsEntity::getAccountId, accountIdList);
            List<RoomJoinsEntity> listOn = roomJoinsMapper.selectList(where);

            //  这个 listOn 是 所以上麦人的消息  上麦人  包括  主持人  嘉宾 助理
            //缓存获取主讲人信息
            Object mainScreenAccountId = redisTemplate.opsForHash().get(RedisKey.INTERACT_GLOBAL + roomId, com.vhall.component.plugin.common.constant.RoomConstant.MAIN_SCREEN);
            for (RoomJoinsEntity roomJoinsEntity : listOn) {
                Integer accountId = roomJoinsEntity.getAccountId();

                Integer isSpeak = 1;
                //当前上麦人的 音屏开关 1 代表 打开  0代表关闭
                Integer audio = users.get(accountId).getAudio();

                //当前上麦人的 摄像头开关 1 代表 打开  0代表关闭
                Integer video = users.get(accountId).getVideo();
                int isMainScreen = 0;
                if ((roomJoinsEntity.getAccountId().toString().equals(String.valueOf(mainScreenAccountId)))) {
                    //看 当前上麦的人  是否是 主讲人
                    isMainScreen = 1;
                }
                GetRoomJoinsDataDTO getRoomJoinsDataDTO = new GetRoomJoinsDataDTO();
                BeanUtils.copyProperties(roomJoinsEntity, getRoomJoinsDataDTO);

                GetRoomJoinsDataDTO jdto = onlineInavAttr(getRoomJoinsDataDTO, isSpeak, audio, video, isMainScreen);
                if (jdto.getRoleName().equals(com.vhall.component.plugin.common.constant.RoomConstant.HOST)) {
                    // 主持人在第一位
                    result.add(0, jdto);
                } else {
                    result.add(jdto);
                }
            }
            return result;
        }

        return result;
    }

    /**
     * 获取已上麦列表用户
     *
     * @param roomId 房间Id
     * @return 从缓存中返回所有已上麦用户的map集合
     */
    private Map<Object, Object> getSpeakerList(String roomId) {
        return redisTemplate.opsForHash().entries(RedisKey.INTERACT_SPEAKER + roomId);
    }

    private GetRoomJoinsDataDTO onlineInavAttr(GetRoomJoinsDataDTO dto, Integer isSpeak, Integer audio, Integer video, Integer isMainScreen) {
        dto.setIsSpeak(isSpeak);
        dto.setAudio(audio);
        dto.setVideo(video);
        dto.setIsMainScreen(isMainScreen);
        return dto;
    }

    /**
     * 进行集合的重构
     *
     * @param list 传入每一个都是GetRoomJoinsDataDTO对象的列表
     * @return 返回传入列表中键为accountId的所有值，并把它加入一个新的结合
     */
    private List<Integer> getAccountIdList(List<GetRoomJoinsDataDTO> list) {
        return list.stream().map(GetRoomJoinsDataDTO::getAccountId).collect(Collectors.toList());
    }

    /**
     * 未上麦的 嘉宾/助理的列表 [已排过序, 嘉宾4,助理3]
     *
     * @param roomId   房间编号
     * @param speakArr 已上麦用户
     * @return
     */
    private LinkedList<GetRoomJoinsDataDTO> getSpecialUsers(String roomId, List<Integer> speakArr) {
        LinkedList<GetRoomJoinsDataDTO> result = new LinkedList<>();
        LambdaQueryWrapper<RoomJoinsEntity> where = Wrappers.lambdaQuery();
        where.eq(RoomJoinsEntity::getRoomId, roomId)
                .ne(RoomJoinsEntity::getRoleName, com.vhall.component.plugin.common.constant.RoomConstant.AUDIENCE)
                .notIn(CollectionUtils.isNotEmpty(speakArr), RoomJoinsEntity::getAccountId, speakArr)
                .orderByDesc(RoomJoinsEntity::getRoleName);

        // 未上麦的 嘉宾/助理的列表
        List<RoomJoinsEntity> listSpecial = roomJoinsMapper.selectList(where);

        for (RoomJoinsEntity entity : listSpecial) {
            GetRoomJoinsDataDTO joins = new GetRoomJoinsDataDTO();
            BeanUtils.copyProperties(entity, joins);
            GetRoomJoinsDataDTO dto = onlineInavAttr(joins, 0, 0, 0, 0);
            result.add(dto);
        }
        return result;
    }

    private Long getOnlineCount(String roomId) {
        Long count = 0L;
        RoomsEntityDTO roomModel = getRoomInfo(roomId);
        if (roomModel != null) {
            count = paasService.getUserOnlineCount(roomModel.getChannelId());
        }
        return count;
    }

    private int calcPages(int total, int size) {
        if (total <= 0) {
            return 0;
        }
        if (total <= size) {
            return 1;
        }
        if (total % size > 0) {
            return (total / size) + 1;
        }
        return (total / size);
    }

    /**
     * 数据类型转换
     *
     * @param room 参数
     * @return RoomsEntityVO
     */
    private RoomsEntityVO convertToRoomsEntityVO(RoomsEntity room) {
        RoomsEntityVO vo = new RoomsEntityVO();
        // 拷贝实体
        BeanUtils.copyProperties(room, vo);
        vo.setName(room.getSubject());
        DateTimeFormatter df = DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT);
        LocalDateTime beginLiveTime = room.getBeginLiveTime();
        if (beginLiveTime == null) {
            Instant instant = Instant.ofEpochMilli(room.getBeginTimeStamp());
            beginLiveTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
        vo.setBeginTime(beginLiveTime.format(df));
        vo.setImage(room.getCoverImage());
        if (room.getStatus() == 0) {
            vo.setStatusStr("待直播");
            vo.setLiveTime(ConstStr.TIME_ZERO);
        }
        if (room.getStatus() == 1) {
            vo.setStatusStr("直播中");
        }
        if (room.getStatus() == 2) {
            vo.setStatusStr("已结束");
        }
        return vo;
    }

}
